﻿using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Lifetime;
using System.Security.Permissions;

namespace IPluginInterface.Loader
{

	[Serializable]
	[SecurityPermission(SecurityAction.Demand, Infrastructure = true)]
	public sealed class Sponsor<TInterface> : ISponsor, IDisposable where TInterface : class {

		private string pluginFilePath;
		private TInterface mInstance;

		/// <summary>
		/// 插件路径
		/// </summary>
		public string PluginFileName
		{
			get
			{
				return pluginFilePath;
			}
			private set
			{
				pluginFilePath = value;
			}
		}

		/// <summary>
		/// 插件实例
		/// </summary>
		public TInterface Instance {
			get {
				if (IsDisposed)
					throw new ObjectDisposedException("Instance");
				else
					return mInstance;
			}
			private set {
				mInstance = value;
			}
		}

		public bool IsDisposed { get; private set; }

		public Sponsor(TInterface instance, string pluginFilename = "") {
			PluginFileName = pluginFilename;
			Instance = instance;

			if (Instance is MarshalByRefObject) {
				object lifetimeService = RemotingServices.GetLifetimeService((MarshalByRefObject)(object)Instance);
				if (lifetimeService is ILease) {
					ILease lease = (ILease)lifetimeService;
					lease.Register(this);
				}
			}
		}

		~Sponsor() {
			Dispose(false);
		}

		public void Dispose() {
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		private void Dispose(bool disposing) {
			if (!IsDisposed) {
				if (disposing) {
					if (Instance is IDisposable) ((IDisposable)Instance).Dispose();

					if (Instance is MarshalByRefObject) {
						var obj = (MarshalByRefObject)(object)Instance;
						if (obj != null)
                        {
							object lifetimeService = RemotingServices.GetLifetimeService(obj);
							if (lifetimeService is ILease)
							{
								ILease lease = (ILease)lifetimeService;
								lease.Unregister(this);
							}
						}
					}
				}

				Instance = null;
				IsDisposed = true;
			}
		}

		/// <summary>
		/// 续订实例上的租约，就像它已正常调用一样。不续约，默认5分钟会被释放掉
		/// </summary>
		/// <param name="lease"></param>
		/// <returns></returns>
		TimeSpan ISponsor.Renewal(ILease lease) {
			if (IsDisposed)
				return TimeSpan.Zero;
			else
				return LifetimeServices.RenewOnCallTime;
		}
	}
}